/*
 * Project it.battlehorse.rcp.tools
 * Created on Nov 18, 2005
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * A copy of the LGPL is available also at
 * http://www.gnu.org/copyleft/lesser.html
 * 
 */
package it.battlehorse.rcp.tools.actions;

import it.battlehorse.rcp.sl.annot.Injected;
import it.battlehorse.rcp.sl.annot.Serviceable;
import it.battlehorse.rcp.tools.Activator;
import it.battlehorse.rcp.tools.actors.ActorDescriptor;
import it.battlehorse.rcp.tools.actors.IActorRegistry;
import it.battlehorse.rcp.tools.actors.IActorRunner;
import it.battlehorse.rcp.tools.views.actorlist.ActorListContentProvider;
import it.battlehorse.rcp.tools.views.actorlist.ActorListLabelProvider;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PlatformUI;

/**
 * The action which is responsible for running the currently open Actor. If multiple
 * actors are open, but noone is selected, a question is raised to the user.
 * If no actors are open, a warning is raised and then the action is aborted.
 * 
 * @author battlehorse
 * @since Nov 27, 2005
 */
@Serviceable
public class RunActorAction extends Action {
	
	/* A reference to a valid Actor runner */
	private IActorRunner runner;
	
	/* A reference to a valid Actor registry */
	private IActorRegistry registry;
	
	/**
	 * Injects a reference to a valid actor runner and a valid registry
	 * 
	 * @param runner an actor runner
	 * @param registry an actor registry
	 */
	@Injected
	public void setActorComponents(IActorRunner runner, IActorRegistry registry) {
		this.runner = runner;
		this.registry = registry;
	}
	
	/**
	 * Creates a new instance of the class
	 *
	 */
	public RunActorAction() {
		super();
		super.setText("&Run Actor@Ctrl+R");
		super.setToolTipText("Executes the currently shown actor");		
		super.setImageDescriptor(Activator.getImageDescriptor("resources/actor/run.png"));
	}
	
	@Override 
	public void run() {
		
		IWorkbenchPartReference activePart = 
			PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePartReference();
					
		ActorDescriptor actor = registry.getActorForView(activePart.getId());
		
		if (actor == null) {
			// The user has not selected an Actor view. If there is only an actor view visible, then
			// we run it. Otherwise, we request the user to select one.
			
			IViewReference[] refs = 
					PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getViewReferences();
			
			List<ActorDescriptor> currentOpenActors = new ArrayList<ActorDescriptor>(); 
			for (IViewReference ref : refs) {
				ActorDescriptor el = registry.getActorForView(ref.getId());
				if (el != null) {
					currentOpenActors.add(el);
				}
			}
			
			if (currentOpenActors.size() == 0) {
				// No actor views seems to be open
				MessageDialog.openWarning(
						PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
						"No actors",
						"You do not have any open actor to be executed");
				actor = null;
			}
			else if (currentOpenActors.size() == 1) {
				actor = currentOpenActors.get(0);
			}
			else {
				MultipleActorDialog dialog = new MultipleActorDialog(currentOpenActors);
				if (dialog.open() == MultipleActorDialog.OK) {
					actor = dialog.getSelectedActor();
					
					// show the selected actor
					String viewId =  actor.getViewId();
					try {
						PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(viewId);
					}
					catch(Exception e) {
						// ignore
					}
					
				}
				else
					actor = null;
			}
		}
		
		if (actor != null)
			runner.runJob(actor.getId());
	}
	
	/**
	 * The dialog which displays the currently open actors to the user.
	 * 
	 */
	private class MultipleActorDialog extends TitleAreaDialog implements ISelectionChangedListener {
		
		private List<ActorDescriptor> actors;
		
		private ActorDescriptor selectedActor;
		
		/**
		 * Creates a new instance of the class
		 * 
		 * @param actors the list of open actors
		 */
		public MultipleActorDialog(List<ActorDescriptor> actors) {
			super(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
			this.actors = actors;
			this.selectedActor = actors.get(0);
		}
		
	    @Override
		protected Control createContents(Composite parent) {
	    	Control c = super.createContents(parent);
	    	
	    	super.setTitle("Actor selection");
	    	super.setMessage("Select the actor you want to execute");
	    	
	    	return c;
	    }
	    
	    @Override
		protected Control createDialogArea(Composite parent) {
	    	Composite c = (Composite) super.createDialogArea(parent);
	    	
	    	Composite comp = new Composite(c, SWT.NONE);
	    	comp.setLayout(new GridLayout(1,false));
	    	
	    	new Label(comp,SWT.NONE).setText("Select the actor you want to execute among the currently active ones:");
	    	
	    	ListViewer viewer = new ListViewer(comp, SWT.BORDER | SWT.V_SCROLL | SWT.SINGLE);	    	
	    	viewer.setContentProvider(new ActorListContentProvider(actors));
	    	viewer.setLabelProvider(new ActorListLabelProvider());
	    	viewer.setInput("root");
	    	viewer.getList().select(0);	// pre-selects the first element
	    	GridData gd = new GridData(GridData.FILL_HORIZONTAL);
	    	viewer.getList().setLayoutData(gd);
	    	viewer.addSelectionChangedListener(this);
	    	
	    	return c;
	    }
	    
	    public void selectionChanged(SelectionChangedEvent e) {
	    	IStructuredSelection sel = (IStructuredSelection) e.getSelection();
	    	this.selectedActor = (ActorDescriptor) sel.getFirstElement();
	    }
	    
	    public ActorDescriptor getSelectedActor() {
	    	return this.selectedActor;
	    }
	    	
	}
	
	

}
